---
menu: Active Proposals
name: focusgroup (Explainer)
layout: ../../layouts/ComponentLayout.astro
---

Authors: [Travis Leithead](https://github.com/travisleithead),
[David Zearing](https://github.com/dzearing),
[Chris Holt](https://github.com/chrisdholt/)

{/* START doctoc generated TOC please keep comment here to allow auto update */}
{/* DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE */}
{/* END doctoc generated TOC please keep comment here to allow auto update */}

## Introduction

Authors create many interactive control [patterns](https://www.w3.org/WAI/ARIA/apg/) that expect
or can benefit from keyboard-accessible behavior such as arrow-key navigation.

This proposal enables authors to add a set of built-in keyboard behaviors for moving focus
among a list or grid of focusable elements without having to write common boilerplate code
(e.g., 
[roving tabindex](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets#technique_1_roving_tabindex))
to do so in their custom controls.

Authors may use the proposed `focusgroup` HTML attribute (or related CSS properties) to declare that
a subtree of focusable elements will get:
1. focus navigation ([not selection](#non-goals)) using keyboard directional arrow keys (for lists
   or grids)
2. a guaranteed tab stop (when at least one focusable element is present)
3. automatic return to the last focused focusable element
4. start/end navigation (with Home/End keys)
5. optional limited-axis arrow key navigation and optional wrap-around semantics

By standardizing `focusgroup`, authors can leverage these behaviors in 
[control patterns](https://www.w3.org/WAI/ARIA/apg/) to provide users with keyboard consistency,
default accessibility, and interoperability over existing solutions.

While this document emphasizes the usage of the keyboard arrow keys for accessibility
navigation, we acknowledge that there are other input modalities that work (or can be adapted
to work) equally well for focusgroup navigation behavior (e.g., game controllers, gesture
recognizers, touch-based ATs, etc.)

## Quickstart

`focusgroup` enables authors to provide keyboard
[roving tabindex](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets#technique_1_roving_tabindex)
with almost no code. Compare the web platform's native
[radio button group](https://html.spec.whatwg.org/multipage/input.html#radio-button-group)
with a custom control using the 
[radio group pattern](https://www.w3.org/WAI/ARIA/apg/patterns/radio/).

<small>Note, this is for illustrative purposes only (see the 
[first rule of ARIA](https://www.w3.org/WAI/ARIA/apg/practices/read-me-first/)).</small>

A platform native radio group:

```html
<p>Choose your pet:</p>
<div id=radiogroup>
  <label>Dog <input type=radio name=mygroup value=dog></label>
  <label>Cat <input type=radio name=mygroup value=cat></label>
  <label>Turtle <input type=radio name=mygroup value=turtle></label>
</div>
```

A custom radio group using `focusgroup`:

```html
<p id=label>Choose your pet:</p>
<div role=radiogroup focusgroup onfocusin="/*update aria-checked values*/" aria-labelledby=label>
  <span role=radio aria-checked=false tabindex=-1>Dog</span>
  <span role=radio aria-checked=false tabindex=-1>Cat</span>
  <span role=radio aria-checked=false tabindex=-1>Turtle</span>
</div>
```

What to notice:
* `focusgroup` enables down/right arrow keys to advance the focus to the next focusable element in
   DOM order (up/left keys will move the focus in reverse) just like in the native radio group.
* `tabindex` is still required to make the `<span>` elements focusable (the `focusgroup` attribute
   doesn't make any elements focusable by default, including the `<div>` it's declared on).
* All the `tabindex` values are set to "-1" and no code has to update those values. `focusgroup` can
   set keyboard focus on elements declared focusable via `tabindex="-1"` via arrow keys. 
   `tabindex="-1"` still prevents these elements from being part of sequential focus navigation 
   (e.g., the "tab sequence")--with one exception: `focusgroup` provides a special behavior that 
   enables one focusable item within the group to get keyboard focus via sequential focus
   navigation even if all the focusable elements within are opting out of sequential focus 
   navigation (i.e., all "focusables" are setting `tabindex=-1`).
* The `onfocusin` event handler is present because `focusgroup` **does not** manage selection state
   (and native radio groups do have selection linked to focus).
* In the native radio group, repeatedly pressing the down arrow key will eventualy wrap the focus
   back around to the first focusable element. In the `focusgroup` example, focus will stop on the
   last focusable element. (But there's an option to turn on wrapping if desired.)
* If the user leaves the focusgroup (via tab key) and returns again, the last element that was 
   focused previously will be the focused element on reentrance (it is remembered).

In this next example, the author is using a 
[tab control pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/) where the tab activation 
behavior is decoupled from selection ("manual tab activation"):

```html
<div role=tablist focusgroup="inline wrap no-memory" aria-label="Common Operating Systems">
  <button id=tab-1 type=button role=tab aria-selected=false aria-controls=tabpanel-1 tabindex=-1>Mac</button>
  <button id=tab-2 type=button role=tab aria-selected=true aria-controls=tabpanel-2 tabindex=0>Windows</button>
  <button id=tab-3 type=button role=tab aria-selected=false aria-controls=tabpanel-3 tabindex=-1>Linux</button>
</div>
<div id=tabpanel-1 role=tabpanel tabindex=0 aria-labelledby=tab-1 hidden> … </div>
<div id=tabpanel-2 role=tabpanel tabindex=0 aria-labelledby=tab-2> … </div>
<div id=tabpanel-3 role=tabpanel tabindex=0 aria-labelledby=tab-3 hidden> … </div>
```

What to notice:
* Sequential focus navigation within a `focusgroup` is respected. When entering the `focusgroup`, 
   focus will always go to the first selected tab (with `tabindex=0`). The `no-memory` value 
   [prevents the focusgroup from remembering the last focused tab](#disabling-focusgroup-memory) so
   that focus will always go to the selected tab on reentrance regardless of which element was 
   focused last.
* If focus is moved via left arrow key to `tab-1`, then pressing the tab key moves focus to the selected
   tab, which is next in sequential focus navigation order. Pressing tab again moves the focus to
   `tabpanel-2` which is next in sequential focus navigation order (because the other 
   `role=tabpanel`s are `hidden`).
* focus will `wrap` from one end of the tablist to the other because of `focusgroup=wrap` attribute 
   value.
* the up and down arrow keys **will not** move the focus because of `focusgroup=inline` which 
   restricts the axis of movement to keyboard directional arrow keys in the `role=tablist`'s
   **inline** direction (assuming the `<div>`'s `writing-mode` is `horizontal-tb`).
* The author code required to manage the selection of a tab is omitted. Such code on tab selection 
   change would update `aria-selected` values, the `hidden` state of the controlled `role=tabpanel`
   and the `tabindex` values of tabs such that the newly selected `role=tab` element is `tabindex=0`
   while all others are `tabindex=-1`.

In a third example, the author is creating a 
[navigation menubar](https://www.w3.org/WAI/ARIA/apg/patterns/menubar/examples/menubar-navigation/).
Both `menuitem`s in the `menubar` ("About" and "Admissions") have popover `menu`s. The "Admissions"
menu has an additional submenu under "Tuition".

```html
<ul role=menubar aria-label="Mythical University" focusgroup="inline wrap">
  <li role=none>
    <a role=menuitem popovertarget=aboutpop href="…" tabindex=-1 title="">About</a>
    <ul role=menu focusgroup="block wrap" autofocus id=aboutpop aria-label=About popover>
      <li role=none><a role=menuitem href="…" tabindex=-1 title="">Overview</a></li>
      <li role=none><a role=menuitem href="…" tabindex=-1 title="">Administration</a></li>
    </ul>
  </li>
  <li role=none>
    <a role=menuitem popovertarget=admitpop href="…" tabindex=-1 title="">Admissions</a>
    <ul role=menu focusgroup="block wrap" autofocus id=admitpop aria-label=Admissions popover>
      <li role=none><a role=menuitem href="…" tabindex=-1 title="">Apply</a></li>
      <li role=none>
        <a role=menuitem popovertarget=tuitpop href="…" tabindex=-1 title="">Tuition</a>
        <ul role=menu focusgroup="block wrap" autofocus id=tuitpop aria-label=Tuition popover>
          <li role=none><a role=menuitem href="…" tabindex=-1 title="">Undergraduate</a></li>
          <li role=none><a role=menuitem href="…" tabindex=-1 title="">Graduate</a></li>
        </ul>
      </li>
      <li role=none><a role=menuitem href="…" tabindex=-1 title="">Visit</a></li>
    </ul>
  </li>
</ul>
```

What to notice:
- `focusgroup` declarations can be nested inside of other focusgroups. When a nested focusgroup
   is declared on an element, it creates a new focusgroup and [opts-out](#opting-out) of its
   ancestor focusgroup.
- menuitems in `role=menubar` are limited to inline-direction arrow keys (e.g., left and right), 
   while menuitems in `role=menu` are limited to block-direction arrow keys (e.g., up and down). 
   This allows the orthogonal arrow keys (e.g., up and down on the menubar, left and right on the 
   menus) to be used for activation purposes (extra code that is not shown in the example).
- Placement of focus on the menus (the nested focusgroups) from the menubar is not a feature of 
   `focusgroup` (nested focusgroups are completely independent of their ancestor focusgroup). In this
   case, the focus placement is handled by built-in `popover` and `autofocus` attribute behaviors.
- the "memory" of the nested `focusgroup`s is reset when the content is hidden/shown--this allows
   the `autofocus` attribute to pick the first focusable element each time a menu is shown--the 
   desired behavior in this case.
   

Here, the author is adding up/down arrow key behavior to focusable headings using an 
[accordion pattern](https://www.w3.org/WAI/ARIA/apg/patterns/accordion/). The arrow keys move the
focus between the headings, but skip anything in the accordion bodies.

```html
<div focusgroup=block>
  <h3><button type=button aria-expanded=true aria-controls=sec1 id=h1>Heading 1</button></h3>
  <div focusgroup=none role=region aria-labelledby=h1 id=sec1>
     … accordion panel w/form controls that are Tab focusable … 
  </div>
  <h3><button type=button aria-expanded=false aria-controls=sec2 id=h2>Heading 2</button></h3>
  <div focusgroup=none role=region aria-labelledby=h2 id=sec2>
     … 2nd panel … 
  </div>
  <h3><button type=button aria-expanded=false aria-controls=sec3 id=h3>Heading 3</button></h3>
  <div focusgroup=none role=region aria-labelledby=h3 id=sec3>
     … 3rd panel … 
  </div>
</div>
```

What to notice:
* The accordion headers only respond to up/down arrow keys because the `focusgroup` is limited to
   the 'block' direction (assuming this content has a `writing-mode` `horizontal-tb`). The headers
   also participate in the sequential focus navigation (i.e., tab order)--`focusgroup` does not 
   change that.
* Any focusable content in the accordion's `role=region` sections is excluded from arrow key 
   navigation via the inclusive opt-out `focusgroup=none`.
* Content in the accordion's `role=region` is still available via sequential focus navigation 
   (e.g., tab order). The tab order is unaffected by `focusgroup=none` declarations.

Finally, the author is creating a data grid following the 
[data grid pattern](https://www.w3.org/WAI/ARIA/apg/patterns/grid/examples/data-grids/) where each
of the cells in the table are focusable.

```html
<table focusgroup=grid role=grid aria-label=Transactions>
  <tbody><tr>
    <th>Date</th>
    <th>Type</th>
    <th>Description</th>
    <th>Amount</th>
    <th>Balance</th>
  </tr>
  <tr>
    <td tabindex=-1>01-Jan-16</td>
    <td tabindex=-1>Deposit</td>
    <td><a tabindex=-1 href=#>Cash Deposit</a></td>
    <td tabindex=-1>$1,000,000.00</td>
    <td tabindex=-1>$1,000,000.00</td>
  </tr>
  <tr>
    <td tabindex=-1>02-Jan-16</td>
    <td tabindex=-1>Debit</td>
    <td><a tabindex=-1 href=#>Down Town Grocery</a></td>
    <td tabindex=-1>$250.00</td>
    <td tabindex=-1>$999,750.00</td>
  </tr>
</tbody></table>
```

What to notice:
- `focusgroup=grid` understands table layout and will provide logical cell navigation with arrow
   keys around all the focusable grid cells.
- `<th>` header cells are not made focusable in this example, and so are not navigable by the
   `focusgroup`.
- all focusable elements are declared with `tabindex=-1` to take them out of sequential focus 
   navigation. The `focusgroup` ensures that at least one of these focusable elements participates
   in the sequential focus navigation order regardless. The `focusgroup` also remembers the last 
   focused element, and returns the user to that element when they re-enter the table via sequential
   focus navigation.

## Goal

The goal of this feature is to "pave the cow path" of an existing authoring practice
(and accessibility best practice) implemented in nearly every Web UI library: the
[roving tabindex](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets#technique_1_roving_tabindex) 
[[react](https://www.npmjs.com/package/react-roving-tabindex), 
[angular](https://material.angular.io/cdk/a11y/overview#listkeymanager), 
[fluent](https://developer.microsoft.com/en-us/fluentui#/controls/web/focuszone), 
[elix](https://component.kitchen/elix/KeyboardDirectionMixin)]].
Note however, that certain design choices have been made to generalize the 
behavior so that additional scenarios are possible. See 
[comparing roving tabindex and focusgroup](https://docs.google.com/document/d/1cOxjjZdvFfpexiN1x-MpNJLXrmbrR0xp1sRCTbaQ29c/)
for further details.

To achieve this goal, we believe the solution must be available in declarative markup or CSS.
If JavaScript is required, then there seems little advantage to using a built-in feature over
what can be implemented completely in author code. Furthermore, a declarative solution provides
the key signal that allows the platform's accessibility infrastructure to make the `focusgroup`
accessible by default:

- signaling to the AT to switch to a 
   ["Focus mode"](https://www.accessibility-developer-guide.com/knowledge/screen-readers/desktop/browse-focus-modes/) 
   by default, e.g., that the user has entered a type of control group.
- allowing user agents to provide visual hints that the use of arrow-key navigation is possible, 
   e.g., through a recognizable focus-ring or visual indicator.
- providing a consistent and reliable navigation usage pattern for users with no extra author code
  required.

## Non-Goals

In some [control patterns](https://www.w3.org/WAI/ARIA/apg/) (such as radio groups or tablists) 
moving the focus to an element also toggles its **selection** state. While some use cases will 
require the selection state to follow the focus, in others these need to be decoupled. `focusgroup`
is decoupled from selection. Tracking and changing selection based on focus will require author 
code. Note that a related proposal for tracking selection state,
[**CSS Toggles**](https://tabatkins.github.io/css-toggle/), is
[no longer being pursued](https://docs.google.com/document/d/10JxXgeDAJ5zerOdxoWM9ZU9d5iMOdzGJt0EhlhkOkxM/).

Implementations are welcome to experiment with additional UI (e.g., a "focusgroup focus ring") in
order to help make users aware of focusgroups, however this proposal does not include any 
specific guidelines or recommendations.

## Principles

1. Intuitive use in declarative scenarios. Focusgroups
   - are easy to reason about (self-documenting) in the source markup or CSS.
   - provide a rational behavior when nested.
   - integrate well with other related platform semantics (e.g., `tabindex`).
1. Focusgroups are easy to maintain and configure.
   - Configuration is managed in one place.
   - Provide easy to understand usage into HTML and CSS patterns.
   - Avoid "spidery connections" e.g., using IDRefs or custom names that are hard to maintain.
1. Complimentary declarative representations in HTML and CSS
   - HTML attributes offers focusgroup usage directly with impacted content and provide for
     the most straightforward scenarios.
   - CSS properties allow for responsive design patterns and can avoid redundant markup in some
     scenarios.

## Use Cases

1. (Element and subtree opt-in) A focusable element and its entire subtree can participate in a
   single focusgroup.
1. (Cross Shadow DOM) Focusable elements contained inside a Shadow DOM are discoverable and 
   focusable when their Shadow Host or an ancestor element declares a focusgroup.
1. (Wrap) Focusgroup can be configured to have wrap-around focus semantics.
1. (Limit directional arrow keys) A focusgroup can be configured to respond to either the logical
   [inline-axis](https://drafts.csswg.org/css-writing-modes-4/#inline-axis) navigation keys (e.g., 
   left and right arrow keys when the focusgroup is in a `horizontal-tb` 
   [writing mode](https://drafts.csswg.org/css-writing-modes/#block-flow)) or 
   [block-axis](https://drafts.csswg.org/css-writing-modes-4/#block-axis) navigation keys or both
   (to trivially reserve one axis of arrow key behavior for supplementary actions, such as opening
   nodes in a tree view control). See 
   [CSS Logical Properties and Values](https://drafts.csswg.org/css-logical/) for more about logical 
   directions.
1. (Focus movement arrow keys follow content direction) The user's arrow key presses move the focus
   forward or backward in the DOM according to the writing mode and directionality of the content. 
   E.g., in RTL, an Arrow-Left key moves the focus forward according to the content direction.
1. (Opt-out) Individual elements can opt-out of focusgroup participation
1. (Grid) Focusgroups can be used for grid-type navigation (`<table>`-structured content or other
   grid-like structured content).

A use case we are evaluating:

1. (Grid) Focusgroups can be used on elements with `display: grid` to provide 2d grid navigation.

## Focusgroup Concepts

A focusgroup is a group of related elements that can be navigated by directional arrow keys and 
home/end keys and for which the web platform provides the navigation behavior by default. No 
JavaScript event handlers needed in many cases! The arrow keys controlling the navigation are mapped 
to "forward" and "reverse" directions according to whether they point in the "block/inline-end" or 
"block/inline-start" directions, respectively (based on the element's directionality that declares 
the focusgroup).

There are two kinds of focusgroups: **linear focusgroups** and **grid focusgroups**.
Linear focusgroups provide arrow key navigation among a _list_ of elements. Grid focusgroups provide
arrow key navigation behavior for tabular (or 2-dimensional) data structures.

| HTML | CSS | Explanation |
|---|---|---|
| `focusgroup` or `focusgroup=""` (no value specified) | `focus-group-type: linear` | Defines a **linear focusgroup** |
| `focusgroup=grid` or `focusgroup=manual-grid` | `focus-group-type: grid` or `focus-group-type: manual-grid` | Defines an automatic grid or manual grid focusgroup. Grid focusgroup are covered in more detail [below](#grid-focusgroups) |

In the case that HTML attribute values conflict with CSS properties, the CSS values override the
HTML-defined values.

Focusgroups consist of a **focusgroup definition** that establishes **focusgroup candidates** and
**focusgroup items**. Focusgroup definitions manage the desired behavior for the associated 
focusgroup items. Focusgroup items are the elements that actually participate in the focusgroup 
(from the set of focusgroup candidates). Focusgroup candidates are all the elements under the scope
of a focusgroup definition. The **focusgroup scope** consists of the element with the focusgroup 
definition and its shadow-inclusive descendants, excluding elements that have opted out.

The minimal focusgroup below demonstrates that the element declaring a focusgroup is also a
focusgroup candidate and (in this case) the single focusgroup item.

```html
<p tabindex=0 focusgroup>World's smallest, but least useful focusgroup</p>
```

Focusgroup candidates become focusgroup items if they are focusable, e.g.,
implicitly focusable elements like `<button>`, or explicitly made focusable via `tabindex` or some
other mechanism (e.g., `contenteditable`, being a scroll-container).

An element can only have _one_ **focusgroup definition** added via the `focusgroup` attribute or 
CSS `focus-group-type: linear` property:

Example:

```html
<p id="ancestor" focusgroup>
  <span>
    <span>
      <span>
        Some text and
        <a id="one" href="…">a link</a>. A
        <span id="two" tabindex="-1">focusable span</span> and
        <a id="three" href="…">another link</a>.
      </span>
    </span>
  </span>
</p>
```

The `ancestor` element has the **focusgroup definition**. The elements with `id=one`, `two`, and 
`three` (and any other shadow-inclusive descendants of `ancestor` that may be added) are 
**focusgroup candidates**. Because each of these candidates are focusable, they are also 
**focusgroup items**. When one of the focusgroup items becomes focused, the user can move focus 
sequentially among all the focusgroup items using the arrow keys (up/right moves focus forward, 
down/left moves focus backwards assuming the `<p>` element has `writing-mode` `horizontal-tb` and
`direction` `ltr`). 

Note that only elements with `id=one` and `three` can be focused using the Tab key. The `<span>` has
`tabindex=-1` set, which takes it out of the tabindex sequential navigation ordering.

### Last-focused memory

By default, focusgroups will remember the last-focused element, and for sequential focus navigation,
will restore focus to that element when a focusgroup is re-entered. This is important for large 
lists or tables so that users are returned the the context they previously left without having to 
navigate from the start or end sequentially.

The focusgroup's memory is initially empty. In that state, sequential focus navigation will pick
the next element to focus using existing platform behavior 
[with the exception noted below](#guaranteed-tab-stop).

The focusgroup's memory is cleared whenever there is any change to the focusability of its 
remembered element or the relationship that the element has with its focusgroup definition element
(such as either one being removed from the tree). See 
[additional details below](#disabling-focusgroup-memory).

### Guaranteed tab stop

Focusgroups provide a special behavior when used in conjunction with sequential focus navigation 
("tab navigation"). Focusgroups ensure that **at least one** focusgroup item will participate in 
sequential focus navigation even if all focusgroup items are declared to opt-out via `tabindex=-1`.
This behavior ensures that a focusgroup can always be entered via sequential focus naviation. 
[See below for further details](#adjustments-to-sequential-focus-navigation). 
Aside from this one behavior change, there is no other impact to the way tab navigation works with
`tabindex` nor the tab ordering behavior.

Focusgroups can therefore be used to provide a 
[roving tabindex](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets#technique_1_roving_tabindex)
among a set of related focusable controls such as this menubar:

Example:

```html
<div role="toolbar" focusgroup aria-label="Text Formatting" aria-controls="…">
  <div>
    <button type="button" aria-pressed="false" value="bold" tabindex="-1"><span>Bold</span></button>
    <button type="button" aria-pressed="false" value="italic" tabindex="-1"><span>Italic</span></button>
    <button type="button" aria-pressed="false" value="underline" tabindex="-1"><span>Underline</span></button>
  </div>
</div>
```

When pressing tab to enter this "toolbar" focusgroup from an element _before_ it, focus will go to
the first `<button>` because:
- There is no other element within the focusgroup with a `tabindex` >= 0 or that is sequentially
   focusable by default (these `<button>`s are taken out of sequential focus navigation with 
   `tabindex=-1`).
- This focusgroup has no "memory" of a last-focused element within (e.g., it has not been entered
   before).
- Since neither of the above cases resulted in focusing an alternate element, then the first 
   focusgroup item in the group is focused.

At this point, the user can use the arrow keys to move from the beginning of the toolbar to the end,
or press tab again to move outside of the focusgroup.

Alternatively, focusgroup can be used to supplement existing tab-stop behavior to provide arrow key
navigational support **in addition** to tab navigation. No problem: just ensure the deisred elements
are sequentially focusable via `tabindex=0` (or stop excluding them via `tabindex=-1`):

Example:

```html
<div role="toolbar" focusgroup aria-label="Text Formatting" aria-controls="…">
  <div>
    <button type="button" aria-pressed="false" value="bold"><span>Bold</span></button>
    <button type="button" aria-pressed="false" value="italic"><span>Italic</span></button>
    <button type="button" aria-pressed="false" value="underline"><span>Underline</span></button>
  </div>
</div>
```

### Shadow DOM boundaries

Focusgroup definitions apply across Shadow DOM boundaries in order to make it easy for component
developers to support focusgroup behavior across component boundaries. (Component authors that want
to [opt-out of this behavior](#opting-out) can do so.)

Example:

```html
<list-component focusgroup role="listbox" aria-label="Cute dogs">
  <template shadowrootmode="open">
    <my-listitem role="option" tabindex="0" aria-selected="true">Terrier</my-listitem>
    <my-listitem role="option" tabindex="-1" aria-selected="false">Dalmation</my-listitem>
    <my-listitem role="option" tabindex="-1" aria-selected="false">Saint Bernard</my-listitem>
  </template>
</list-component>
```

### Key conflicts

The focusgroup is a default handler for certain keystrokes (keydown events for arrow keys, home/end,
etc.) that will cause focus to move among focusgroup items. This default keyboard handling could
interfere with other actions the application would like to take. A common pattern is to 
[limit focusgroup directionality](#limiting-linear-focusgroup-directionality) so that certain 
cross-axis keystrokes won't trigger focusgroup behavior. However, if these doesn't address the use
case, then authors may cancel the focusgroup's default behavior at any time by canceling
(`preventDefault()`) the specific keydown event. Keydown events are dispatched by the currently 
focused element, and bubble through the focusgroup ancestor element in most cases.

### Interactive content inside focusgroups

Some built-in controls like `<input type=text>` provide keyboard behaviors that "trap" nearly all 
keys that would be handled by the focusgroup. Others such as `<input type=number>` trap only certain
keys like the arrow keys that are also used for focusgroup navigation. This proposal **does not** 
provide a built-in workaround to prevent this from happening. Instead, authors are advised to be 
sure users can "escape" these elements. Built-in elements provide this via the tab key. Other
strategies might include requiring an "activation" step before putting focus into the interactive
control (and an Esc key exit to leave).

The focusgroup's [memory](#last-focused-memory) may also cause unexpected user interactions if 
authors are not careful. For example, without any author mitigations, an interactive control inside
a focusgroup may inadvertently prevent the user from accessing other focusgroup items:

```html
<div role=toolbar focusgroup aria-label="Font Adjustment" aria-controls="…">
  <label for=font-input>Font</label>
  <div>
    <div>
      <input type=text id=font-input role=combobox aria-autocomplete=both aria-expanded=false aria-controls=font-listbox aria-activedescendant="">
      <button type=button aria-label="Font List" aria-expanded=false aria-controls=font-listbox tabindex=-1>🔽</button>
    </div>
    <ul id=font-listbox role=listbox aria-label="Font List">
      <li role=option>Ariel</li>
      <li role=option>Monospace</li>
      <li role=option>Verdana</li>
    </ul>
  </div>
  <button type=button value="bigger" tabindex=-1><span>Increase Font</span></button>
  <button type=button value="smaller" tabindex=-1><span>Decrease Font</span></button>
</div>
```

When the `combobox` input element is focused, it is remembered by the focusgroup's memory.
The `<input>` element traps nearly all keystrokes by default, including the arrow keys that might 
have been used to reach the "Increase/Decrease Font" buttons. When the user presses tab, focus
exits the focusgroup. Later, when focus re-enters, the focusgroup will put focus back on the 
`<input>` element (because of the memory), and the cycle continues with no way to get to the two
following buttons via keyboard interaction alone.

Fortunately, there are several solutions to this problem:
- Remove `tabindex=-1` from the "Increase/Decrease Font" buttons.
- Move the "Increase/Decrease Font" buttons before the `combobox`. (Refer to "Avoid including 
   controls whose operation requires the pair of arrow keys used for toolbar navigation" in the 
   [Toolbar control pattern](https://www.w3.org/WAI/ARIA/apg/patterns/toolbar/).) Additionally, 
   [opt-out](#opting-out) the `<input>` control from focusgroup participation so that 
   arrow keys skip it. Alternatively, 
   [turn off the focusgroup's memory](#disabling-focusgroup-memory) so that focus isn't 
   automatically returned to the `combobox`.
- Use script to intercept focusgroup-related keydown events on the `<input>` and move focus 
   manually. Also consider [limiting the focusgroup](#limiting-linear-focusgroup-directionality) to
   one axis and reserving the other axis for operating the `<input>`.   

### Restricted elements

Because focusgroup definitions are intended for grouping related controls, it does not make sense
to provide focusgroup functionality on all elements. While the focusgroup attribute may de defined
as a global attribute, it's applicability is limited to a subset of elements.

At the time of writing, we are evaluating which elements will honor a focusgroup attribute 
definition. We welcome comments on this section. To submit your feedback, please see the issue
[Restrict usage of focusgroup on certain elements](https://github.com/openui/open-ui/issues/1007).

The current proposal is to limit focusgroup to only the elements whose name match the DOM's 
[valid shadow host names](https://dom.spec.whatwg.org/#valid-shadow-host-name) (which are the 
elements allowed to call `attachShadow()`). However, `<table>` and some table parts will need to
be an exception in order to properly support grid focusgroups.

### Feature detection

To enable feature detection, the DOM will include a `focusgroup` property, whose existence on 
elements is useful for feature detection.

```webidl
partial interface HTMLElement {
  [CEReactions] attribute DOMString focusgroup;
};
```

### Additional features

Focusgroups have the following additional features:

- [Wrap-around semantics](#enabling-wrapping-behaviors) - what to do when attempting to move past
   the end of a focusgroup. The default/initial value is `no-wrap`, which means that focus is
   not moved past the ends of a focusgroup with the arrow keys. `wrap` and other tabular wrapping
   behaviors are available for `grid` focusgroups.
- [Directional axis limits](#limiting-linear-focusgroup-directionality) - applies to linear
   focusgroups only; respond to arrow keys in one axis only (either up/down or left/right when the
   arrow key pressed matches the corresponding flow of the content). By default, linear focusgroups
   respond to all four arrow keys.
- [Focusgroup candidacy opt-out](#opting-out) - prevent an element and its 
   shadow-inclusive descendants from participating in an anscester's focusgroup.
- [Memory opt-out](#disabling-focusgroup-memory) - prevent the focusgroup from remembering what the 
   last focused element was when focus leaves a focusgroup. By default focusgroups remember that 
   element and will restore the focus to that element when the focusgroup is re-entered via 
   sequential focus navigation.

In HTML these feature options are applied as space-separated token values to the `focusgroup`
attribute. In CSS, these definitions are specified as properties (including a `focus-group` 
shorthand property for convenience).


## Enabling wrapping behaviors

By default, focusgroup traversal with arrow keys ends at boundaries of the focusgroup (the start and
end of a linear focusgroup, and the start and end of both rows and columns in a grid focusgroup). 
The following focusgroup definition values change this behavior:

| HTML | CSS | Explanation |
|---|---|---|
| (default) `focusgroup=""` (unspecified) | `focus-group-wrap: none` | Disables any kind of wrapping. |
| `focusgroup=wrap` | `focus-group-wrap: wrap` | Causes movement beyond the ends of the focusgroup to wrap around to the other side. |

Additional values are available for grid focusgroups. Note, row and column-specific wrapping
and flowing can be specified together: `focus-group-wrap` supports two-token specifiers for
this purpose.

| HTML | CSS | Explanation |
|---|---|---|
| (default) `focusgroup="grid"` | `focus-group-wrap: none` or `focus-group-wrap: row-none col-none` | Rows and columns do not wrap or flow (default). |
| `focusgroup="grid wrap"` | `focus-group-wrap: wrap` or `focus-group-wrap: row-wrap col-wrap` | Movement at the ends of the rows/columns wrap around to the opposite side of the same rows/columns. |
| `focusgroup="grid row-wrap"` | `focus-group-wrap: row-wrap` or `focus-group-wrap: row-wrap col-none` | Rows wrap around, columns do not wrap. |
| `focusgroup="grid col-wrap"` | `focus-group-wrap: col-wrap` or `focus-group-wrap: col-wrap row-none` | Columns wrap around, rows do not wrap. |
| `focusgroup="grid flow"` | `focus-group-wrap: flow` or `focus-group-wrap: row-flow col-flow` | Movement past the end of a row wraps the focus to the beginning of **the next row**. Movement past the beginning of a row wraps focus back to the end of **the prior row**. Same for columns. The last row/column wraps to the first row/column and vice versa. |
| `focusgroup="grid row-flow"` | `focus-group-wrap: row-flow` or `focus-group-wrap: row-flow col-none` | Rows "flow" from row ends to the next/prior row as described above, columns don't wrap or flow. |
| `focusgroup="grid col-flow"` | `focus-group-wrap: col-flow` or `focus-group-wrap: col-flow row-none` | Columns "flow" from column ends to the next/prior column as described above, rows don't wrap or flow. |
| `focusgroup="grid row-wrap col-flow"` | `focus-group-wrap: row-wrap col-flow` | Rows wrap around, and columns flow (as described above). |
| `focusgroup="grid row-flow col-wrap"` | `focus-group-wrap: row-flow col-wrap` | Rows flow (as described below) and columns wrap around. |

Specifying both `row-wrap` and `row-flow` in one HTML focusgroup definition is an author error. Only
one declaration for row behavior is allowed. Similarily for `col-wrap` and `col-flow`.


## Limiting linear focusgroup directionality

In many cases, having multi-axis directional movement (e.g., both right arrow and down arrow linked
to the forward direction) is not desirable, such as when implementing a 
[tablist control pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/), in which case it may not
make sense for the up and down arrows to also move the focus left and right. Likewise, when moving
up and down in a vertical menu, the author might wish to use JavaScript to provide other behavior
for the left and right arrow keys such as opening or closing sub-menus. In these situations, authors
can limit the linear focusgroup to one-axis traversal.

Note that the following only apply to linear focusgroup definitions (they have no effect on grid
focusgroups).

| HTML | CSS | Explanation |
|---|---|---|
| (default) `focusgroup=""` (unspecified) | `focus-group-direction: both` | The focusgroup items will respond to forward and backward movement with both directions (horizontal and vertical). The default/initial value. |
| `focusgroup=inline` | `focus-group-direction: inline` | The focusgroup items will respond to forward and backward movement only with arrow keys that are parallel to this element's "inline" axis (e.g., left and right arrow keys for `horizontal-tb` writing mode). |
| `focusgroup=block` | `focus-group-direction: block` | The focusgroup items will respond to forward and backward movement only with arrow keys that are parallel to this element's "block" axis (e.g., up and down arrow keys for `vertical-*` writing modes). |

Example:

```html
<tab-group role=tablist focusgroup="inline wrap">
  <a-tab role=tab tabindex=0 aria-selected=true aria-controls="…">…</a-tab>
  <a-tab role=tab tabindex=-1 aria-selected=false aria-controls="…">…</a-tab>
  <a-tab role=tab tabindex=-1 aria-selected=false aria-controls="…">…</a-tab>
</tab-group>
```

In the above example, when the focus is on the first `<a-tab>` element, pressing either the up or
down arrow key does nothing because the focusgroup is configured to only respond to the inline
(left/right in this case) arrow keys.

Because 2-axis directionality is the default, specifying both `inline` and `block` at the
same time on one focusgroup is not allowed:

Example:

```html
<!-- This is an example of what NOT TO DO -->
<radiobutton-group focusgroup="inline block wrap" role=radiogroup>
  ⚠️This focusgroup configuration is an error--neither constraint will be applied (which is actually
  what the author intended).
</radiobutton-group>
```


## Opting-out

Focusgroup definitions assigned to an element create focusgroup candidates that include 
the element itself and all its _shadow-inclusive descendant elements_. Any element within that
focusgroup scope that is (or becomes) focusable will automatically become a focusgroup item 
belonging to its ancestor's focusgroup.

With such an expansive opt-in behavior, it is important to provide an opt-out for elements or
element subtrees. For example: focusable elements that wish to remain in sequential focus 
navigation and have arrow key navigation pass them over; or, components nested across a 
Shadow DOM boundary that wish to be excluded from focusgroup participation.

Opting-out applies to the element making the declaration as well as its shadow-inclusive 
descendants.

To opt-out:

| HTML | CSS | Explanation |
|---|---|---|
| `focusgroup=none` | `focus-group-type: none` | Opt-out of a focusgroup: this element and its shadow-inclusive descendants will not be considered focusgroup candidates. |

In the following example of an [accordion pattern](), the accordion's panels opt-out of `focusgroup`
behavior so that any interactive content in a panel is bypassed when navigating among the 
accordion headers.

Example:

```html
<div focusgroup=block>
  <h3>
    <button type=button aria-expanded=true aria-controls=sec1 id=h1>Heading 1</button>
  </h3>
  <div focusgroup=none role=region aria-labelledby=h1 id=sec1> … accordion panel w/form controls that are Tab focusable … </div>
  <h3>
    <button type=button aria-expanded=false aria-controls=sec2 id=h2>Heading 2</button>
  </h3>
  <div focusgroup=none role=region aria-labelledby=h2 id=sec2> .. 2nd panel … </div>
  <h3>
    <button type=button aria-expanded=false aria-controls=sec3 id=h3>Heading 3</button>
  </h3>
  <div focusgroup=none role=region aria-labelledby=h3 id=sec3> .. 3rd panel … </div>
</div>
```

When a focusgroup definition is appled to an element, it implicicly opts out of any ancestor's 
focusgroups. This ensures that every element can only belong in one focusgroup at a time.

Example:

```html
<div focusgroup> <!-- Parent -->
  <div focusgroup> <!-- implicit focusgroup=none -->
    <button>Am I a candidate, if yes, for which group?</button>
    <div focusgroup></div> <!-- what happens here? -->
  </div>
</div>
```

- `<-- Parent -->` is a `focusgroup` that currently has no focusable candidates in it. If other 
   children are added to it, then they and their descendants would be candidates for inclusion in
   that Parent focusgroup.
- `<button>` is in the focusgroup declared by its parent.
- `<-- what happens here? -->` declares another focusgroup with no focusable candidates. At the same
   time it is also opting itself out of inclusion in the focusgroup that includes the `<button>`.


## Disabling focusgroup memory

By default, when a linear or grid focusgroup is defined it includes a "memory" of the
last-focused element within its scope, initially empty. Each time the focus is changed
within a focusgroup, the "memory" is updated to refer to that element. This behavior is
akin to the 
[roving tabindex](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets#technique_1_roving_tabindex)
in which the "memory" is the statefull `tabindex=0` value assigned to the currently
focused element.

In some scenarios it is not desireable to have a focusgroup maintain a memory. Usually this
is because there is a more relevant element which should take focus when entering the focusgroup
instead of the most-recently-focused element. For example, an active (selected) tab in a 
`role=tablist` container, rather than the last-focused tab (when selection does not follow focus).

To disable the focusgroup's default memory, use the value `no-memory`:

| HTML | CSS | Explanation |
|---|---|---|
| (default) `focusgroup=""` (unspecified) | `focus-group-memory: auto` | The focusgroup will remember the last-focused element and redirect focus to it when entered via sequential focus navigation. |
| `focusgroup=no-memory` | `focus-group-memory: none` | The focusgroup will not remember the last-focused element. |

After the focusgroup's memory has been set, it must be cleared whenever any one of the following
change:

* The element with the focusgroup definition is `hidden` or un-hidden; or if the currently-remembered
   element is `hidden` or un-hidden.
* The element with the focusgroup definition has its `disabled` or `inert` status changed; or if the 
   currently-remembered element has its `disabled` or `inert` status changed.
* The element with the focusgroup definition is removed from the shadow-inclusive tree; or if the 
   currently-remembered element is removed from the shadow-inclusive tree.
* The currently-remembered element stops being focusable (e.g., a `<div>` with a `tabindex` has its
   `tabindex` attribute removed).
* The currently-remembered element is changed to become excluded from the focusgroup (through 
   `focusgroup=none` on itself or a shadow-inclusive ancester, or by changing focusgroups: if a new
   focusgroup definition appears on itself or one of its shadow-inclusive ancestor elements).


## Adjustments to sequential focus navigation

To ensure that a focusgroup always has at least one tab stop in the sequential focus navigation 
order, and to provide the appropriate "hook" for a focusgroup's "memory" to redirect focus to the
last-focused element in a focusgroup, a change to sequential focus navigation is needed.

This change is intended to ensure that focus is directed to one of the following focusgroup
candidates whenever focus enters a focusgroup. The first matching condition is always taken:

1. If there is an element in the focusgroup memory, focus is set on that element.
1. If there is an element with `tabindex=0` (or other built-in element with UA-defined keyboard 
    focusability like `<input>`, `<button>`, etc.) that is also a focusgroup candidate for the
    current focusgroup, focus will be set on the first such element in DOM order (regardless of
    the direction of traversal, i.e., via `tab` or `Shift+tab`). Note: this provides authors with a 
    predictable "entry" of their choosing within a focusgroup.
1. The first focusable element (even if not intended for sequential focus navigation) if sequential
    focus navigation is moving "forward", or the last focusable element if sequential focus
    navigation is traversing "backward".

Specifically, each focusgroup definition must maintain a:
* first focusable focusgroup candidate - in DOM order, the first focusable element that is also a 
   focusgroup candidate (e.g., not excluded from focusgroup participation or in another focusgroup).
* last focusable focusgroup candidate - see previous, but the **last** focusable in DOM order.
* first sequentially-focusable focusgroup candidate - in DOM order, the first focusable element that
   would participate in sequential focus navigation order (e.g., the element with the lowest 
   positive value of `tabindex`, or with `tabindex=0`, or that is a built-in sequentially focusable
   element that has not opted-out via `tabindex=-1`).

Algorithmically, during "forward" sequential focus navigation, if the element being considered is:
1. a member of a focusgroup AND is the first focusable focusgroup candidate of that focusgroup THEN:
   1. if the focusgroup's memory is available and not empty, then move focus to the element referred
       to by the focusgroup's memory.
   1. otherwise, if there is NO first sequentially-focusable focusgroup candidate in that 
       focusgroup, then move focus to this element.
1. otherwise, continue with the sequential focus navigation algorithm as normal.

For "reverse" sequential focus navigation, the algorithm is similar, but swap occurances of the
"first focusable focusgroup candidate" for "last focusable focusgroup candidate".

Because this algorithm applies only when interrogating the first (or last) focusable focusgroup
candidate, then any descendants that preceed (or follow) the first (or last) focusable 
focusgroup candidate that themselves define a focusgroup are considered first. In other words,
broad-reaching ancestral focusgroups won't necessarily "steal" focus from descendant focusgroups 
during sequential focus navigation.

## Grid focusgroups

Some focusable data is structured not as a series of nested linear groups, but as a
2-dimensional grid such as in a spreadsheet app, where focus can move logically from
cell-to-cell either horizontally or vertically. In these data structures, it makes
sense to support the user's logical usage of the arrow keys to move around the data.

Grid navigation is expected to happen within well-structured content with consistent
rows and columns where DOM structure reflects this organization. In focusgroup grid 
navigation, only the cells in the grid are focusgroup candidates and only the focusable 
cells become focusgroup items. It is not currently possible to use grid focusgroups to 
support other focusable tabular parts such as focusable row elements (see 
[comment in issue 1018](https://github.com/openui/open-ui/issues/1018#issuecomment-2013053227) for
a possible future addition for this use case).

### Applicability to tabular data

The arrow navigation in the grid (and in the previous non-grid scenarios) should
reflect the accessible structure of the document, not the presentation view made
possible with CSS. For example, it is easy to create views that visually appear
grid-like, but do not make sense to navigate like a grid if considering that the
data model is fundamentally a list, which is how users of accessibility technology
would perceive it. Wrapping a list of contact cards on screen in a grid-like
presentation allows for more content density on screen for sighted users. In that
scenario, arrow key navigation to move linearly (left-to-right following the
line-breaking across each line) through the contents makes sense (especially if
these are alphabetized), but orthogonal movement through the "grid" (up/down when
cards are aligned or in a masonry layout) jumps the focus to seemingly arbitrary
locations. Multi-directional arrow key navigation may seem appropriate for sighted
users that have the visual context only, but are not appropriate for assistive
technology. In the case of the list-presented-as-a-grid scenario, a linear
focusgroup will make the most sense for sighted as well as users with accessibility
needs.

When considering using a grid focusgroup, be sure that the data is structured
like a grid and that the structure makes semantic sense in two dimensions (and not
just for a particular layout or presentation).

Tabular data can be structured using column-major or row-major organization. Given
that HTML tables and ARIA attributes for grids (`role=grid`, `role=row`, `role=gridcell`)
only exist for row-major grid types, this proposal does **not define** grid focusgroup
organization for column-major data structures (and assumes row-major data structures
throughout).

### Setting up a grid focusgroup

Grid focusgroups can be created "automatically" or manually. Automatic grids use the context
of existing HTML semantics for tables as the structural components necessary to provide grid-based
navigation. Any elements with computed table layout are suitable for an automatic grid (e.g.,
`display: table-row` in place of using a `<tr>` elements). 
[Manual grid](#manual-grids-row-and-cell-connections) creation requires 
annotating specific elements with their focusgroup grid component names.

Note: We are evaluating the suitability for CSS `display: grid` to create automatic grids.

The automatic grid approach will be preferable when the grid contents are uniform
and consistent and when re-using semantic elements for grids (typical). The manual
approach may be necessary when the grid structure is not uniform or structurally
inconsistent (atypical), and involves identifying the parts of the grid on specific
focusgroup candidates using CSS.

Elements with the `grid` focusgroup definition on the root element of the structural
grid become automatic grid focusgroups. The implementation must attempt to validate
the structure of the grid to ensure it has appropriate row and cell structures. In the
event that the implementation cannot automatically determine the grid structure, then
the definition is ignored (i.e., there is no fallback to a linear grid).

| HTML | CSS | Explanation |
|---|---|---|
| `focusgroup=grid` | `focus-group-type: grid` | Establishes the root of an automatic grid focusgroup. Shadow-inclusive descendants of the automatic grid are identified and assigned `focus-group-type: grid-row` and `focus-group-type: grid-cell` focusgroup candidate status automatically. |

Example:

```html
<table aria-label="Tic tac toe grid" role=grid focusgroup=grid>
  <tr>
    <td tabindex=-1></td>
    <td tabindex=-1></td>
    <td tabindex=-1></td>
  </tr>
  <tr>
    <td tabindex=-1></td>
    <td tabindex=-1></td>
    <td tabindex=-1></td>
  </tr>
  <tr>
    <td tabindex=-1></td>
    <td tabindex=-1></td>
    <td tabindex=-1></td>
  </tr>
</table>
```

The `<table>`'s grid focusgroup definition automatically establishes each of its
descendant `<tr>`s as focusgroup rows (the parser-generated `<tbody>` is
accounted for) and `<td>`s as focusgroup cells. Each focusgroup cell is a scope
root for one focusgroup item per cell, and the cell and its shadow-inclusive decendants are all
focusgroup candidates. Among all focusgroup cells, the left/right arrow keys navigate between cells
in the table, and up/down arrow keys will compute the new target based on the DOM position of the
current focusgroup candidate cell in relation to the focusgroup candidate row.

### Manual grids: row and cell connections

A manual grid is declared in a focusgroup definition with the name `manual-grid`.
With a manual grid, the rows and cells must be explicitly indicated using `grid-row` and 
`grid-cell`:

| HTML | CSS | Explanation |
|---|---|---|
| `focusgroup=manual-grid` | `focus-group-type: manual-grid` | Establishes the root of a manual grid focusgroup. Shadow-inclusive descendants of the manual grid must be identified with `focus-group-type: grid-row` and `focus-group-type: grid-cell` explicitly. |
| `focusgruop=grid-row` | `focus-group-type: grid-row` | Must be a shadow-inclusive descendant of a grid focusgroup root (i.e., the `manual-grid`-named focusgroup element). |
| `focusgroup=grid-cell` | `focus-group-type: grid-cell` | Must be a shadow-inclusive descendant of a grid focusgroup root (i.e., the `manual-grid`-named focusgroup element). Must also be a shadow-inclusive descendant of a `focus-group-type: grid-row` focusgroup candidate. |

Cells cannot be descendants of other cells, and rows cannot be descendants of other rows.

Each focusgroup candidate will perform an ancestor search to locate its nearest grid structural
component: cells will look for their nearest row, and rows will look for their nearest grid root.

In the following example, the `<my-cell>`s are all meant to be on the same row of the
grid, and the rows are designated by `<my-row>` elements:

Example:

```html
<my-root role=grid focusgroup=manual-grid>
  <div role=none class=presentational_wrapper>…</div>
  <my-row role=row focusgroup=grid-row>
    <first-thing role=gridcell focusgroup=grid-cell>…</first-thing>
    <cell-container role=none>
      <my-cell role=gridcell focusgroup=grid-cell>…</my-cell>
      <my-cell role=gridcell focusgroup=grid-cell>…</my-cell>
    </cell-container>
    <cell-container role=none>
      <my-cell role=gridcell focusgroup=grid-cell>…</my-cell>
      <my-cell role=gridcell focusgroup=grid-cell>…</my-cell>
    </cell-container>
  </my-row focusgroup=grid-row>
  <!-- repeat pattern of div/my-row pairs... -->
</my-root>
```

The following non-uniform structure can still have grid semantics added
via `manual-grid`:

Example:

```html
<div role=grid focusgroup="manual-grid flow">
  <div role=row focusgroup=grid-row>
    <div>
      <div role=gridcell focusgroup=grid-cell></div>
      <div role=gridcell focusgroup=grid-cell></div>
    </div>
  </div>
  <div>
    <div role="row" focusgroup=grid-row>
      <div role=gridcell focusgroup=grid-cell></div>
      <div role=gridcell focusgroup=grid-cell></div>
    </div>
  </div>
  <div>
    <div>
      <div role="row" focusgroup=grid-row>
        <div>
          <div role=gridcell focusgroup=grid-cell></div>
          <div role=gridcell focusgroup=grid-cell></div>
        </div>
      </div>
    </div>
  </div>
</div>
```

### Grid focusgroup nesting

Unlike linear focusgroups, an automatic or manual grid focusgroup requires a small degree of DOM
structure to work correctly. Unless the proper structure exists, the grid focusgroup won't work.

Attempts to define new grid or linear focusgroups among the DOM elements that makeup the
structure of a grid focusgroup (such as on or between elements defining the root grid
container, the grid-rows and the grid-cells) will be ignored. However new grid or linear
focusgroups **can be defined** on elements that are shadow-inclusive descendants of grid-cell
elements (e.g., that are outside the set of elements making up the grid's DOM structure).


### Empty Cell data

Like linear focusgroups, focus is only set on elements that are focusable. The arrow key navigation
algorithms look for the first focusgroup item (in DOM order) of a grid focusgroup cell in the
direction the arrow was pressed. Non-focusable grid focusgroup candidates of a focusgroup cell
are passed over in the search.

### Non-uniform cells

It is entirely possible to have rows with non-uniform numbers of cells. In these
cases, focusgroup navigation behaviors may not work as visibly desired. Algorithms
for navigating grid focusgroups will work based on content the grid content structure
as specified. If the algorithms conclude that there is no "next candidate cell" to
move to (e.g., in a grid with two rows, and the bottom row has three cells, and the
top row only two, if the focus is on the 3rd cell, a request to move "up" to the prior
row cannot be honored because there is no "3rd cell" in that row.

## Privacy and Security Considerations

### Privacy

No considerable privacy concerns are expected, but we welcome community feedback.

### Security

No significant security concerns are expected.

## Design decisions

Here is a short list to issue discussions that led to the current design of focusgroup.

* [`focusgroup` works across Shadow DOM boundaries by default](https://github.com/openui/open-ui/issues/521)
* [arrow key movement and directionality contraints should be aligned with content direction (add inline/block)](https://github.com/openui/open-ui/issues/522)
* [focusgroup definitions should not be limited to direct-children](https://github.com/openui/open-ui/issues/989)
* [focusgroup should include a memory](https://github.com/openui/open-ui/issues/537)


## Alternative Solutions

We considered various alternative solutions before arriving at the current proposal:

1. We considered a design more closely aligned with HTML's radio button groups, wherein
   to form a 'focusgroup' each participating element used a similarly-named moniker.
   The platform was expected to automatically link same-named groups together. This
   enabled groups to be widely dispersed across the DOM. In practice few scenarios
   require that degree of flexibility and data locality helps ensure that lists of
   items stay relatively adjacent to each other structurally. Furthermore, this approach
   provided no common "controller" element, and additional attributes were proposed to
   potentially link these groups together. Finally, this proposal suggested that the
   attribute also enable the element to get keyboard focus if it didn't already have
   it--another new way of making elements focusable wasn't deemed a great idea.
2. In another iteration, we considered codifying the ARIA authoring practices applying
   platform behavior automatically based on the presence of certain ARIA attributes
   (such as role="tab"). This idea didn't get too far, as we ultimately felt that
   aria attributes really shouldn't have native behavior locked into them as that sets
   a bad precedent. It was also considered that aria in some fundamental ways is a
   patch on top of the native HTML engine for support that should eventually become
   a native part of the platform. That was the insight that took us in the direction
   of building a native HTML feature to expose the built-in platform arrow-key
   navigation of certain controls.

## Related Work

### CSS Basic UI 4 Keyboard Navigation properties

[Since at least 2002](https://www.w3.org/TR/2002/WD-css3-ui-20020802/#nav-dir) the CSS WG
has defined related CSS properties `nav-up`, `nav-right`, `nav-down`, `nav-left` in
[CSS Basic UI 4's Keyboard Control](https://drafts.csswg.org/css-ui-4/#keyboard). These
properties are expected to provide focus navigation control similar to `focusgroup`. They
differ in some significant ways:

- `nav-*` are defined using CSS (vs HTML). Not that HTML-without-CSS is really a modern
  concern, but proposing focusgroup in HTML enables the user agent to setup focusgroups
  without the CSS dependency (or behavior change should CSS application be delayed due to
  network conditions).
- Each of `nav-up`, etc., require an explicit content selector (id) for ordering, which
  makes them relatively brittle. This design presents at least three challenges:
  - The possibility of mis-alignment to content. If stylesheet `nav-*` selectors are not
    updated in terms of changes to document content (at authoring time) the navigation
    expectations can get out of sync.
  - Unexpected side-effects with responsive design. If the wrapping and reflow of
    presentational content changes depending on device characteristics (such as orientation,
    zoom level), authors must likely provide dynamic run-time updates to `nav-*` properties
    in order to keep top/left/bottom/right navigation logical per the current layout.
  - Related to the previous point, it can be easy to make logical errors in navigation
    sequences when targeting specific directions. This can lead to directions that don't
    match the property names (e.g., `nav-left` actually navigates up or right) while also
    opening up the possibility of unidirectional navigation (e.g., after navigating right,
    the user can't go "back" to the left due to missing or erroneous selectors).
- Ordering is not based on content. These properties serve visual presentations, but possibly
  make focus navigation illogical for accessibility users (especially when _any_ element
  can be targeted by selector).
- Verbose descriptors. To get four-direction navigation on one element requires specifying
  four unique CSS properties.
- Special focus handling. The use of a selector on one of the `nav-*` properties has the unique
  property of making that element focusable upon keyboard navigation to it. Additional
  clarity on how this special semantic applies would be needed for implementation. It
  is unclear (especially given the related Note in the spec) if this is a desirable
  behavior.

In nearly 20 years, user agents have not implemented these properties. It is likely that
`focusgroup` will create an incongruency in the platform with these `nav-*` CSS properties.
Should the two exist simultaneously, the `nav-*` properties might provide override semantics
for directional movement, and take precedence over the `focusgroup` attribute. However, we
hope that such a conflict will not occur.

### Spatial Navigation

Another approach to focusable navigation has been defined in
[CSS Spatial Navigation](https://drafts.csswg.org/css-nav-1/). This specification enables
user agents to deterministically navigate focusable elements in logical directions
(top, left, bottom, and right) according to those element's visual presentation. It assumes
that a user agent will use some undefined trigger to enter a "spatial navigation mode" in
which the specification-defined behavior will apply. This mechanism of navigating content
can be an alternative (or addition to) traditional TAB key navigation (or equivalent) for
a variety of devices (like TVs).

Spatial navigation occurs in the context of a "spatial navigation container" which defaults
to any scroll container (e.g., the viewport). The specification provides an API to enable
programmatic navigation, and offers several CSS properties: to enable additional spatial
navigation containers, to control the behavior of focus and scroll actions by navigation
keys, and to customize the algorithm used for finding the next focusable element in a given
direction.

The specification does not presume to use spatial navigation in a limited (e.g., scoped
and grouped) way as `focusgroup` implies. It appears to assume that arrow key direction
navigation will be a primary navigation technique, thus any and all focusable content
should participate.

It may be possible for Spatial Navigation and `focusgroup` to coexist simultaneously in
the same content. In the case that spatial navigation is only enabled via a special mode,
it would be likely that its navigation model would take precedence over `focusgroup`, as
it is meant to make all visual, focusable content navigable, and would provide a
super-set of navigational movement for visual content. It is worth noting that accessibility
tools would not likely enable spatial navigation mode.

It seems desirable to have a feature to easily enable spatial-navigation-like behavior
for a subset of elements in a presentation. While this would not be ideal for an
accessibility-view of the content, it is possible that particular spatial navigation metaphors
could be omitted by accessibility tools when performing navigation. For example, when an
AT interfaces with the user agent, the AT might limit navigation to "forward/backward" content
navigation modes, while a user not working with an AT (or ATs designed for visual navigation)
would enable the full spatial navigation model. An opt-in for spatial navigation would certainly
be a requirement and could be an extension to `focusgroup` (e.g., `focusgroup=spatial`).

## Open Questions

* [Issue 995](https://github.com/openui/open-ui/issues/995) - It may not make sense to support 
   focusgroup on every HTML element, especially those that already have platform-provided 
   focusgroup-like internal behavior (e.g., `<select>`). Then again, if the key navigation 
   behavior is explained by the presence of an external attribute on these elements, perhaps
   the internal behavior should defer to the external specified behavior (usage of the attribute
   would cancel the element's preexisting built-in behavior in favor of the new generic behavior).
   Implementation experience and additional community feedback will be necessary to land a 
   reasonable plan for this case.

See other [open focusgroup issues on Github](https://github.com/openui/open-ui/issues?q=is%3Aissue+is%3Aopen+label%3Afocusgroup).

## Additional Keyboard support

In addition to arrow keys, the focusgroup should also enable other navigation keys such as
pageup/down for paginated movement (TBD on how this could be calculated and in what
increments), as well as the home/end keys to jump to the beginning and end of groups.

It might also be interesting to add support for typeahead scenarios (though what values to
look for when building an index would need to be worked out, and may ultimately prove to be
too complicated).

## Index of focusgroup values

***Focusgroup types:***

| Description | HTML syntax | CSS syntax |
|---|---|---|
| no focusgroup | (missing/invalid attribute) | `focus-group-type: none` |
| linear focusgroup | (unspecified value; default value) | `focus-group-type: linear` |
| automatic grid focusgroup | `grid` | `focus-group-type: grid` |
| manual grid focusgroup root | `manual-grid` | `focus-group-type: manual-grid` |
| manual grid focusgroup row | `grid-row` | `focus-group-type: grid-row` |
| manual grid focusgroup cell | `grid-cell` | `focus-group-type: grid-cell` |

***Focusgroup directions:***

| Description | HTML syntax | CSS syntax |
|---|---|---|
| both directions for a linear focusgroup | (unspecified value; default value) | `focus-group-direction: both` |
| inline direction for a linear focusgroup | `inline` | `focus-group-direction: inline` |
| block direction for a linear focusgroup | `block` | `focus-group-direction: block` |

***Focusgroup wrapping:***

| Description | HTML syntax | CSS syntax |
|---|---|---|
| no wrap | (unspecified value; default value) | `focus-group-wrap: none` |
| wrap | `wrap` | `focus-group-wrap: wrap` |
| flow (grid focusgroups only) | `flow` | `focus-group-wrap: flow` |
| column specific | `col-wrap`, `col-flow`, `col-none` | `focus-group-wrap: col-wrap` or `col-flow` or `col-none` |
| row specific | `row-wrap`, `row-flow`, `row-none` | `focus-group-wrap: row-wrap` or `row-flow` or `row-none` |

***Focusgroup memory:***

| Description | HTML syntax | CSS syntax |
|---|---|---|
| enable memory | (unspecified value; default value) | `focus-group-memory: auto` |
| disable memory | `no-memory` | `focus-group-memory: none` |


## Acknowledgments

Thanks to the members of the OpenUI Community Group for their many contributions. Special thanks to
those who have reviewed, commented on, filed issues, and talked with us offline about focusgroup. 
Your insight and ideas and contributions have been indispensible.
